#include "../../config.h"

#include <glibmm/i18n.h>

#include "../application.h"
#include "p_input.h"
#include "p_macros.h"

namespace gpyp {
namespace pref {

//========================
// Input::Selector
Input::Selector::Selector(Application &app) {
  RefConfInput input = app.conf().input();
  set_active(add(input->mainwindow(), _("Main window")));
  add(input->channellist(),   _("Channel list"));
  add(input->process(),       _("Process"));
  add(input->peercast(),      _("PeerCast"));
  add(input->pc_relay(),      _("PeerCast relay"));
  add(input->pc_connection(), _("PeerCast connection"));
  add(input->text_editor(),   _("Text editor"));
  add(input->search(),        _("Search"));
  add(input->searchbar(),     _("Search bar"));
}

//========================
// Input::Key
void Input::KeyList::accel_on_cell_data(Gtk::CellRenderer   *cell,
                                        const Gtk::TreeIter &iter) {
  RefKeyBindEntry entry = get_item(iter);
#ifdef GTK_HAVE_CELL_RENDERER_ACCEL
  Gtk::CellRendererAccel *renderer =
    dynamic_cast<Gtk::CellRendererAccel *>(cell);
  renderer->property_accel_key()  = entry->accel()->get_key();
  renderer->property_accel_mods() = entry->accel()->get_mods();
#else
  CellRendererAccel *renderer = dynamic_cast<CellRendererAccel *>(cell);
  renderer->set(entry->accel()->get_key(), entry->accel()->get_mods());
#endif
}
void Input::KeyList::accel_on_accel_edited(const Glib::ustring &path_string,
                                           guint                accel_key,
                                           Gdk::ModifierType    accel_mods,
                                           guint              /*keycode*/) {
  RefKeyBindEntry entry = get_item(path_string);
  entry->accel()->set(accel_key, accel_mods);
}
void Input::KeyList::command_on_cell_data(Gtk::CellRenderer *cell,
                                          const Gtk::TreeIter &iter) {
  dynamic_cast<Gtk::CellRendererText *>(cell)
    ->property_text() = *get_item(iter)->command();
}
void Input::KeyList::command_on_edited(const Glib::ustring &path,
                                       const Glib::ustring &new_text) {
  get_item(path)->command() = new_text;
}

void Input::KeyList::set(RefKeyBind keybind) {
  ListView<KeyBind>::set(keybind);
}

Input::KeyList::KeyList() :
  column_accel_  (_("Key"),     renderer_accel_),
  column_command_(_("Command"), renderer_command_)
{
#define CELL_DATA(N)                                                    \
  column_##N##_.set_cell_data_func(renderer_##N##_, sigc::mem_fun(*this, &KeyList::N##_on_cell_data))
  CELL_DATA(accel);
  CELL_DATA(command);
#undef CELL_DATA

  renderer_accel_.property_editable() = true;
  renderer_accel_.signal_accel_edited()
    .connect(sigc::mem_fun(*this, &Input::KeyList::accel_on_accel_edited));
  renderer_command_.property_editable() = true;
  renderer_command_.signal_edited()
    .connect(sigc::mem_fun(*this, &Input::KeyList::command_on_edited));

  append_column(column_accel_);
  append_column(column_command_);
}

//========================
// Input
void Input::reset_button_command() {
  if (selected_ex_) {
    selected_ex_->command()->detach(mouse_ex_.property_text());
    selected_ex_.reset();
  }
  if (selected_) {
    selected_ex_ =
      selected_->mouse()[mouse_ex_selector_.get_active_row_number() + 10];
    if (selected_ex_) {
      selected_ex_->command()->attach(mouse_ex_.property_text());
    }
    mouse_ex_.set_sensitive(true);
  } else {
    mouse_ex_.set_sensitive(false);
  }
}

void Input::set(ConfInput::RefInputEntry input) {
#define INPUT_MOUSE_CONNECT(CONN, NAME)         \
  selected_->mouse()->NAME()->command()->       \
    CONN(mouse_##NAME##_.property_text())
  if (selected_) {
    if (selected_->mouse()) {
      INPUT_MOUSE_CONNECT(detach, double_click);
      INPUT_MOUSE_CONNECT(detach, button2);
      INPUT_MOUSE_CONNECT(detach, button6);
      INPUT_MOUSE_CONNECT(detach, button7);
      INPUT_MOUSE_CONNECT(detach, button8);
      INPUT_MOUSE_CONNECT(detach, button9);
    }
  }
  selected_ = input;
  if (selected_) {
    mouse_.set_sensitive(selected_->mouse());
    key_  .set_sensitive(selected_->key());
    if (selected_->mouse()) {
      INPUT_MOUSE_CONNECT(attach, double_click);
      INPUT_MOUSE_CONNECT(attach, button2);
      INPUT_MOUSE_CONNECT(attach, button6);
      INPUT_MOUSE_CONNECT(attach, button7);
      INPUT_MOUSE_CONNECT(attach, button8);
      INPUT_MOUSE_CONNECT(attach, button9);

      reset_button_command();

      if (selected_ == app_.conf().input()->webview()) {
        mouse_double_click_.set_sensitive(false);
        mouse_button2_     .set_sensitive(false);
      } else {
        mouse_double_click_.set_sensitive(true);
        mouse_button2_     .set_sensitive(true);
      }
    }
    if (selected_->key()) {
      key_list_.set(selected_->key());
    }
  } else {
    mouse_.set_sensitive(false);
    key_  .set_sensitive(false);
  }
#undef INPUT_MOUSE_CONNECT
}

Input::Input(Application &app, Gtk::Window &/*parent*/) :
  Gtk::VBox(false, 2),
  app_     (app),
  selector_(app),
  mouse_   (_("Mouse")),
  key_     (_("Key"))
{
  pack_start(selector_, false, false);

  for(size_t i = 10; i <= 20; ++i) {
    mouse_ex_selector_.append_text(format(_("Button%i"), i));
  }
  mouse_ex_selector_.set_active(0);

  Gtk::Table *t1 = Gtk::manage(new Gtk::Table());
  TABLE_LABEL(*t1, 0, _("Double click"));
  TABLE_LABEL(*t1, 1, _("Button2"));
  TABLE_LABEL(*t1, 2, _("Button6"));
  TABLE_LABEL(*t1, 3, _("Button7"));
  TABLE_LABEL(*t1, 4, _("Button8"));
  TABLE_LABEL(*t1, 5, _("Button9"));
  t1->attach(mouse_double_click_, 1, 2, 0, 1);
  t1->attach(mouse_button2_,      1, 2, 1, 2);
  t1->attach(mouse_button6_,      1, 2, 2, 3);
  t1->attach(mouse_button7_,      1, 2, 3, 4);
  t1->attach(mouse_button8_,      1, 2, 4, 5);
  t1->attach(mouse_button9_,      1, 2, 5, 6);
  t1->attach(mouse_ex_selector_,  0, 1, 6, 7, Gtk::SHRINK | Gtk::FILL);
  t1->attach(mouse_ex_,           1, 2, 6, 7);
  t1->set_col_spacings(2);
  t1->set_row_spacings(2);
  t1->set_border_width(2);
  mouse_.add(*t1);
  pack_start(mouse_, false, false);

  Gtk::ScrolledWindow *sw1 = Gtk::manage(new Gtk::ScrolledWindow());
  sw1->add(key_list_);
  sw1->set_shadow_type(Gtk::SHADOW_IN);
  sw1->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
  Gtk::Button *b_a = Gtk::manage(new Gtk::Button(Gtk::Stock::ADD));
  Gtk::Button *b_r = Gtk::manage(new Gtk::Button(Gtk::Stock::REMOVE));
  b_a->signal_clicked().connect(sigc::mem_fun(key_list_, &KeyList::add));
  b_r->signal_clicked().connect(sigc::mem_fun(key_list_, &KeyList::remove));
  Gtk::HButtonBox *h1 =
    Gtk::manage(new Gtk::HButtonBox(Gtk::BUTTONBOX_END, 2));
  h1->pack_start(*b_a, false, false);
  h1->pack_start(*b_r, false, false);
  Gtk::VBox *v1 = Gtk::manage(new Gtk::VBox(false, 2));
  v1->pack_start(*sw1);
  v1->pack_start(*h1, false, false);
  v1->set_border_width(2);
  key_.add(*v1);
  pack_start(key_);

  set(selector_.get_active());
  selector_.signal_selected()
    .connect(sigc::mem_fun(*this, &Input::set));
  mouse_ex_selector_.signal_changed()
    .connect(sigc::mem_fun(*this, &Input::reset_button_command));
}

}/*pref*/
}/*gpyp*/
